home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-03-03 | 36.8 KB | 1,613 lines |
- COMMENT $
-
- CMACROS - assembly macros for interfacing to HLL
-
- (C)Copyright Microsoft Cor. 1990
-
- $
-
- ; Revision History
- ; 6.0 Initial Release of cmacros for MASM 6.0
- ;
-
- COMMENT $
-
- ; Note: There are some differences between this version of CMACROS
- ; and previous releases. The most signification is the fact
- ; that locals and parameter names are now scoped to the body
- ; of a procedure. To help ease this problem we have introduced
- ; a new directive cRet. This means that the following transformation
- ; can occur on your source to deal with parameters no referenced
- ; in the body of a procedure
- ;
- ; cProc cProc
- ; locals,parms locals,parms
- ; cBegin cBegin
- ; .... ...
- ; cEnd cRet
- ; error code referencing error code referencing
- ; locals and parms locals and params
- ; cEnd <nogen>
- ;
- ; The major reason for making locals and parameters scoped was
- ; the percieved benifit of error checking for defined labels in
- ; the procedure and the addition of codeView information on locals
- ; and parameters for functions.
-
- $
- .xcref ; Get rid of alot of symbols
-
- ; ??_out - output the given message to the console unless ?QUIET
- ; has been specified
- ;
- ; usage:
- ; ??_out <t>
- ; where:
- ; <t> is the message to output
-
- ??_out macro t
- ifndef ?QUIET
- echo t
- endif
- endm
-
- ; outif - output msg if name is non-zero. If name is undefined,
- ; set name =0, else set name to the default value.
- ;
- ; usage:
- ; outif name, defval, onmsg, offmsg
- ; where:
- ; name name of symbol
- ; defval default value to give symobl if not defined.
- ; if blank, then 0 will be used
- ; onmsg text to display if symbol is non-zero
- ; offmsg text to display if symbol is zero
- ;
-
- outif macro name:req, defval:=<0>, onmsg, offmsg
- ifndef name
- name = defval
- endif
- if name
- name = 1
- ifnb <onmsg>
- ??_out <! onmsg>
- endif
- else
- ifnb <offmsg>
- ??_out <! offmsg>
- endif
- endif
- endm
-
-
- ; ??error - output message and generate an assembly time error
- ;
- ; usage:
- ; ??error <t>
- ; where:
- ; t is the text to output
- ;
-
- ??error macro msg
- echo e r r o r ------ msg ;; to console
- .err e r r o r ------ msg ;; forced error by assembler
- endm
-
- ??_out <cMacros Version 6.00 - 1/1/91>
- ??_out <Copyright (C) Microsoft Corp. 1990-1991. All rights reserved.>
-
- ;
- ; Determine the memory model for cmacros. Default to small if
- ; no other model has been specified.
- ;
-
- ifdef ?SMALL
- memS=1
- endif
- ifdef ?MEDIUM
- memM=1
- endif
- ifdef ?COMPACT
- memC=1
- endif
- ifdef ?LARGE
- memL=1
- endif
- ifdef ?HUGE
- memH=1
- endif
-
-
- outif memS,0,<Small Model>
- outif memM,0,<Medium Model>
- outif memC,0,<Compact Model>
- outif memL,0,<Large Model>
- outif memH,0,<Huge Model>
-
- memMOD = memS + memM + memL + memC + memH
- if memMOD ne 1
- if memMOD eq 0
- memS=1 ; Assume small model
- outif memS,0,<Small Model>
- else
- ??error <must have only 1 memory model selected>
- endif
- endif
-
- sizec = memM + memL + memH ; Large Code models
- sizeC = sizec
- sized = memC + memL + memH ; Large Data models
- sizeD = sized
-
- ;
- ; Inform user of any other options selected
- ;
-
- outif ?DF,0,<No segments or groups will be defined>
- outif ?DFDATA,0,<No data segments will be defined>
- outif ?DFCODE,0,<No code segments will be defined>
- outif ?TF,0,<Epilogue sequences will assume valid SP>
- outif ?WIN,1,<Windows support>
- outif ?COW,0,<Character Windows support>
- outif ?PLM,1,<PL/M calling convention>
- outif ?NOATOMIC,0,<ATOMIC calling convention>
- outif ?NODATA,0,<NODATA module>
-
- ifdef ?CHKSTK
- ifdef ?CHKSTKPROC
- ??_out <! Private stack checking enabled>
- else
- ??_out <! Stack checking enabled>
- endif
- else
- ?CHKSTK = 0
- endif
-
- ifndef ?DOS5
- ?DOS5 = 0
- endif
-
- ;
- ; Setup some local variables to the Cmacros package
- ;
-
- ??CM_state = 0 ; 0 - inactive, 1-cProc, 2-cBegin,
- ??CM_RegSaveList textequ <> ; List of saved registers
- ??CM_ArgList textequ <>
-
- ;
- ; This function is used to paste together two text items to
- ; get a third text item.
- ;
-
- ??CM_Paste macro arg1:req, arg2:req
- exitm <arg1&arg2>
- endm
-
- ;
- ; This function is used to create a text macro containning the
- ; n-th local to a fuction definition.
- ;
-
- ??CM_addLocal macro arg1:req
- ??CM_Paste(??CM_local, %??CM_localCount) textequ <LOCAL arg1>
- ??CM_localCount = ??CM_localCount + 1
- endm
-
- ;
- ; This function is used to create a text macro containning the
- ; n-th parameter to a function definition
- ;
-
- ??CM_addParm macro arg1:req
- if ??CM_argCount EQ 20
- .err <CMACROS.INC: Cannot have more than 20 arguements to a procedure>
- endif
- ??CM_Paste(??CM_arg, %??CM_argCount) textequ <, arg1>
- ??CM_argCount = ??CM_argCount + 1
- endm
-
- ;
- ; This macro creates the prologue code for a cmacro defined function.
- ;
- ; Prologue sequences
- ;
-
- cPrologue macro procname, flags, cbParms, cbLocals, reglist, userparms
-
- ?ba=0 ;;not in a procedure
- ?pu=0 ;;initial public setting
- ?ia=0 ;;no special prolog/epilog
- ?rp=0 ;;no register parameters
- ??CM_UserDoesFrame=0 ;;don't use makeframe
- ?ff=0 ;;don't force frame setup
- ?pas=0 ;;process register save list
- ?pcc=?PLM ;;calling convention (C or PL/M)
-
-
-
- ;;
- ;; Look at all of the user parameters and make appropriate decisions
- ;;
-
- for x,<userparms>
- ifdef ??CM_Paste(??_cproc_, x)
- ??CM_Paste(??_cproc_, x)
- else
- ??error <e r r o r - unknown keyword x>
- .err
- endif
- endm
-
- ;;
- ;; Now start some error checking
- ;;
-
- if (??CM_Atomic eq 1) and (??CM_NoData eq 0) ;;ATOMIC requires NODATA
- ??error <ATOMIC specified without NODATA - ATOMIC ignored>
- ??CM_Atomic = 0 ;;clear the ATOMIC keyword
- endif
-
- if flags AND 020h ;;if a far procedure
- if ??CM_WinFarProc ;;if windows
- ife ??CM_Atomic ;;if not ATOMIC
- ife ?COW ;; COW dos not save DS
- ?ia=2 ;; adjust locals for saved ds
- ; ?pas = ?pas and (not ?ds) ;;no need for extra save
- endif
- endif
- endif
- else
- ??CM_WinFarProc=0 ;;not a far windows procedure
- endif
-
- ; ?pas = ?pas and (not (?sp+?cs+?ss)) ;;make no sense to save these
-
- if ??CM_UserDoesFrame ;;don't save these if user frame
- ; ?pas = ?pas and (not (?bp+?si+?di))
- endif
-
- if ??CM_UserDoesFrame ;;if user frame
- if ??CM_NoData
- ??error <NODATA encountered in &n - user frame ignored>
- ??CM_UserDoesFrame=0
- endif
- endif
-
- if ??CM_UserDoesFrame ;;if user frame
- if ?rp ;;If register parameters
- ??error <parmR encountered in &n - user frame ignored>
- ??CM_UserDoesFrame=0
- endif
- endif
-
- ?cpd=0 ;;terminate current proc def
-
- ifidn <g>,<nogen> ;;if nogen, then cannot have locals
- if cbLocals + cbParms + ?rp ;; saved regs, or parmRs
- ??_out <cBegin - possibly invalid use of nogen>
- endif
- else ;;else must generate a frame
-
- ;;
- ;; Allow the user to specify his own routine which is going to
- ;; do the frame set-up for this procedure
- ;;
-
- if ??CM_UserDoesFrame ;;if user frame code specified
- ?mf c,cbLocals,%?po ;; call user's makeframe
- for reg,reglist ;; save specified registers
- push reg
- endm
- else
-
- if ??CM_WinFarProc ;;if a far windows procedure
- ife ??CM_NoData ;;if not NODATA,
- mov ax,ds ;; then set AX = current ds, and ;@
- nop ;; leave room for MOV AX,1234h ;@
- endif
-
- ife ??CM_Atomic ;;if not ATOMIC, far frame must be set
-
- ife ?DOS5 ;;if not DOS5, then set far frame flag
- inc bp ;; by incrementing the old bp ;@
- endif
-
- push bp ;@
- mov bp,sp ;@
-
- ife ?COW ;; save DS not needed for CW
- push ds ;@
- endif
-
- else ;;ATOMIC procedure
-
- if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
- push bp ;; then must set frame pointer ;@
- mov bp,sp ;; to be able to access them ;@
- endif
-
- endif
-
- ife ??CM_NoData ;;if not NODATA, then AX should
- mov ds,ax ;; have the ds to use ;@
- endif
-
- else ;;not windows. use standard prolog
-
- if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
- push bp ;; then must set frame pointer ;@
- mov bp,sp ;; to be able to access them ;@
- endif
- endif
-
- if ?rp ;;if parmR's, push them before
- ??CM_UserDoesFrame=0 ;; allocating locals and saving
- rept ?rp ;; the autosave registers
- uconcat mpush,,?rp,%??CM_UserDoesFrame
- ??CM_UserDoesFrame=??CM_UserDoesFrame+1
- endm
- endif
-
- if cbLocals ;;if locals to allocate
- if ?CHKSTK ;;if stack checking enabled
- ifdef ?CHKSTKPROC ;;if user supplied stack checking
- ?CHKSTKPROC %cbLocals ;; invoke it with bytes requested
- else
- mov ax,cbLocals ;;invoke default stack checking ;@
- ife cc
- call _chkstk ;@
- else
- call chkstk ;@
- endif
- endif
- else ;;no stack checking
- sub sp,cbLocals ;; allocate any local storage ;@
- endif
- endif
- endif
-
- for reg,reglist ;;save autosave registers
- push reg
- endm
- endif ;; No Gen
-
- ifdef ?PROFILE ;;if profiling enabled
- if c ;; and a far procedure
- call StartNMeas ;; invoke profile start procedure ;@
- endif
- endif
-
- exitm %(cbLocals+?ia)
- endm
-
- ;
- ; This macro will define the epilogue sequences for CMACROS
- ; functions.
- ;
- ; Epilog sequences
-
- cEpilog macro procname, flags, cbParms, cbLocals, reglist, userparms
- if ??CM_nogen ;; Nogen the cEnd --
- exitm
- endif
-
- ?ba=0 ;;no longer in a procedure
-
- ifidn <g>,<nogen> ;;if nogen, then cannot have parmRs
- if a+r+lc ;; locals, or saved registers
- ??_out <cEnd - possibly invalid use of nogen>
- endif
- else ;;else must remove the frame
- ifdef ?PROFILE ;;if profiling enabled
- if flags AND 020H ;; and a far procedure
- call StopNMeas ;; invoke profile stop procedure
- endif ;; (doesn't trash DX:AX)
- endif ;; ?PROFILE
- for reg,reglist ;;restore autosaved registers
- pop reg
- endm
- if ??CM_UserDoesFrame ;;if to use the "makeframe" procedure
- db 0c3h ;; near return to user's makeframe @
- else
- if ??CM_WinFarProc ;;if far win proc, use special epilog
- ife ??CM_Atomic ;;if not ATOMIC, bp was pushed
- ife ?COW ;; restore DS not needed for CW
- if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
- lea sp,-2+[bp] ;; or locals or parmR's, get valid SP @
- endif
- pop ds ;;restore saved ds and bp @
- else
- if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
- mov sp,bp
- endif
- endif
- pop BP ;; @
- ife ?DOS5 ;;if not DOS5, bp was
- dec BP ;; incremented to mark far frame @
- endif
- else ;;ATOMIC frame was set up
- if memS32
- leave
- else
- if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
- mov SP,BP ;; or locals or parmR's, get valid SP @
- endif
- if cbLocals+cbParms+?rp
- pop BP ;@
- endif
- endif
- endif
- else ;;non-windows standard epilog
- if ?ff+cbLocals+cbParms+?rp ;;if any parameters
- if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid SP
- mov SP,BP ;; or locals or parmR's, get valid SP;@
- endif
- pop BP ;@
- endif
- endif ;; Far Win Proc
- ife flags AND 010H ;;if Pascal calling convention
- ret cbParms ;; return and remove paramteres ;@
- else ;;else
- ret ;; return ;@
- endif
- endif ;; User makes frame
- endif ;; noGen
- endm
-
- ;
- ; cProc - This macro is used to define the start of a procedure in CMACROS.
- ;
- ; PARAMETERS:
- ; pname - The name of the procedure to be defined. This field is
- ; required to be present.
- ; attribs - This is a list of attributes which may be placed on the
- ; function being defined.
- ; autoSave - This is an optional list of registers which are to be
- ; saved and restored during the prologue/epilogue processing
- ;
-
-
- cProc macro pname:REQ, attribs, autoSave
-
- IF ??CM_state NE 0 ;; No nesting of functions allowed
- .err <CMACROS.INC: Cannot nest procedure definitions>
- endif
- ;
- ; Setup some state variables to start the procedure definition
- ;
- ??CM_state = 1 ;; Set state variable to seen cProc
- ??CM_ProcName EQU <pname>
- ??CM_ProcAutoSave EQU <autoSave>
- ??CM_localCount = 0
- ??CM_argCount = 0
- ??CM_langType EQU <>
- ??CM_WinFarProc=?WIN ;;default far procedure (win or not)
- ??CM_NoData=?NODATA ;;default NODATA flag
- ??CM_Atomic=?NOATOMIC ;;default is not ATOMIC
- repeat 20 ;; Clear all parameter textmacros
- ??CM_Paste(??CM_arg, %??CM_argCount) textequ <>
- ??CM_argCount = ??CM_argCount + 1
- endm
- ??CM_argCount = 0
-
- ife sizec ;; Set the default distance
- dist equ <NEAR>
- else
- dist equ <FAR>
- endif
-
- vis equ <> ;; Set the default visibility
-
- for arg,<attribs> ;; Look at the attribute list
- ifidn <arg>, <FAR>
- dist equ <FAR>
- elseifidn <arg>,<NEAR>
- dist equ <NEAR>
- elseifidn <arg>,<PUBLIC>
- vis equ <PUBLIC>
- elseifidn <arg>,<PRIVATE>
- vis equ <PRIVATE>
- elseifidn <arg>,<LOCAL> ;; Ignore -- only for CRT
- elseifidn <arg>,<PASCAL>
- ??CM_langType equ <PASCAL>
- elseifidn <arg>,<C>
- ??CM_langType equ <C>
- elseifidn <arg>,<WIN>
- ??CM_WinFarProc=1
- elseifidn <arg>,<NOWIN>
- ??CM_WinFarProc=0
- elseifidn <arg>,<NODATA>
- ??CM_NoData=1
- elseifidn <arg>,<ATOMIC>
- ??CM_Atomic=1
- else
- % .err <CMACROS.INC: cProc -- Unknown arguement '&arg'>
- endif
- endm
-
- option prologue:cPrologue ;; Change to our prologue sequence
- option epilogue:none ;; rets from here on are just rets
-
- endm
-
-
- ;
-
- cBegin macro pname
- local t2
- IF ??CM_state NE 1 ;; Must follow cProc
- .err <CMACROS.INC: cBegin must follow a cProc>
- endif
- ??CM_nogen = 0
- ifnb <pname>
- ifidn <pname>,<nogen>
- ??CM_nogen = 1
- elseifdif ??CM_ProcName, <pname>
- % echo <cBegin name (&pname) must match name on preceding cProc (&??CM_ProcName>
- endif
- endif
- ??CM_state = 2 ;; Seen a cBegin
- % setDefLangType ??CM_langType
- macroarg EQU <>
- ifnb ??CM_ProcAutoSave
- ??uses CATSTR <uses >, ??CM_ProcAutoSave
- t2 = @InStr(, %??uses, <,>)
- while t2 NE 0
- ??uses CATSTR @SubStr(<%??uses>, 1, %t2-1), < >, @SubStr(<%??uses>, %t2+1)
- t2 = @InStr(, %??uses, <,>)
- endm
- else
- ??uses textequ <>
- endif
- ifidn defLangType,<C>
- % ??CM_Paste(_, %??CM_ProcName) textequ <??CM_ProcName>
- endif
-
- ??CM_ProcName proc dist defLangType vis macroarg ??uses ??CM_arg0 ??CM_arg1 ??CM_arg2 ??CM_arg3 ??CM_arg4 ??CM_arg5 ??CM_arg6 ??CM_arg7 ??CM_arg8 ??CM_arg9 ??CM_arg10 ??CM_arg11 ??CM_arg12 ??CM_arg13 ??CM_arg14 ??CM_arg15 ??CM_arg16 ??CM_arg17 ??CM_arg18 ??CM_arg19
- ??CM_ProcAutoSave EQU <>
- t2 = 0
- repeat ??CM_localCount
- ??CM_Paste(??CM_local, %t2)
- t2 = t2 + 1
- endm
- endm
-
-
- ;
-
- cEnd macro pname
- IF ??CM_state NE 2 ;; Must follow a cEnd
- .err <cEnd must follow a cProc>
- endif
-
- ??CM_nogen = 0
-
- ifnb <pname>
- ifidn <pname>,<nogen>
- ??CM_nogen = 1
- elseifdif ??CM_ProcName, <pname>
- % echo <cEnd name (&pname) must match preceeding cProc name (&??CM_ProcName)>
- endif
- endif
-
- option epilogue:cEpilog
- ret
- option prologue:prologuedef
- option epilogue:epiloguedef
- ??CM_ProcName endp
- ??CM_state = 0 ;; not in a function
- endm
-
- ;
- ;
-
- cRet macro
- IF ??CM_state NE 2 ;; Must follow a cBegin
- .err <cRet must follow a cProc>
- endif
-
- option epilogue:cEpilog
- ret
- option epilogue:none
- endm
-
-
- ;
- ; createSeg is a macro that sets up a segment definition and
- ; a logical name for that segment. The logical name can
- ; be used to egner the segment, but it cannot be used for anyting
- ; else.
- ;
- ; usage:
- ; createSeg n, ln, a, co, cl, grp
- ; where:
- ; n is the physical name of the segment
- ; ln is the name it is to be invoked by
- ; a is the alignment, and is optional
- ; co is the combine type, and is optional
- ; cl is the class, and is optional
- ; grp is the name of the group that contains the segment
- ;
-
- createSeg macro segName, logName, aalign, combine, class, grp
- ifnb <class>
- segName segment aalign combine '&class'
- else
- segName segment aalign combine
- endif
- segName ends
- ifnb <grp>
- grp GROUP segName
- logName&OFFSET equ offset grp:
- logName&BASE equ grp
- else
- logName&OFFSET equ offset segName:
- logName&BASE equ segName
- endif
-
- logName&_sbegin macro
- segName segment
- sEnd macro name
- ifnb <name>
- ifdifi <name>,<logName>
- % echo <sEnd name does not match sBegin logName>
- endif
- endif
- segName ends
- purge sEnd
- endm
- endm
-
- ifnb <grp>
- logName&_assumes macro s
- assume s:grp
- endm
- else
- logName&_assumes macro s
- assume s:segName
- endm
- endif
- endm
-
- sBegin macro name:req
- name&_sbegin
- endm
-
- ; assumes is a macro that will set up the assumes for a segment
- ; or group created with the createSeg macro. If the assumed
- ; value passed in isn't known, then a normal assume is made.
- ;
- ; usage:
- ; assumes s,g
- ;
- ; where:
- ; s is the register to make the assumption about
- ; g is the value to assume is in it
-
-
- assumes macro s,ln
- ifndef ln&_assumes
- assume s:ln
- else
- ln&_assumes s
- endif
- endm
-
- ;
- ; defGrp
- ;
-
- defGrp macro foo:vararg
- endm
-
- ; setDefLangType
-
-
- setDefLangType macro overLangType
- ifnb <overLangType>
- ifidn <overLangType>,<C>
- defLangType textequ <C>
- elseifidn <overLangType>,<PASCAL>
- defLangType textequ <PASCAL>
- elseifidn <overLangType>,<PLM>
- defLangType textequ <PASCAL>
- else
- % .err <Illegal Language Type specified 'overLangType'>
- endif
- else ; !nb <overLangType>
- if ?PLM EQ 1
- defLangType textequ <PASCAL>
- elseif ?PLM EQ 0
- defLangType textequ <C>
- else
- .err <Illegal value for ?PLM>
- endif
- endif ; nb <overLangType>
- endm
-
-
- ifndef ?NOSTATIC
-
- .xcref
- .xcref staticB, staticW, staticD, staticQ, staticT, staticCP, staticDP, staticI
- .cref
-
- ; staticX - define static data of type X
- ;
- ; usage:
- ; staticX n, i, s
- ;
- ; where:
- ; X is the type of the variable: b=byte, w=word, d=dword
- ; q=quad word, t=ten bytes, cp=code pointer,
- ; dp=data pointer, i=int
- ; n is the name of the given variable
- ; i is the initial value of the variable
- ; s is the duplication factor
- ;
- ; statics are always pascal symbols and non-public. If they are required
- ; to be public then globalX should be used.
-
- staticB macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name db repCount dup (initVal)
- else
- name db initVal
- endif
- endm
-
- staticW macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name dw repCount dup (initVal)
- else
- name dw initVal
- endif
- endm
-
- staticD macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name dd repCount dup (initVal)
- else
- name dd initVal
- endif
- endm
-
- staticI macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name asmI repCount dup (initVal)
- else
- name asmI initVal
- endif
- endm
-
- staticQ macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name dq repCount dup (initVal)
- else
- name dq initVal
- endif
- endm
-
- staticT macro name:req, initVal:=<?>, repCount
- ifnb <repCount>
- name dt repCount dup (initVal)
- else
- name dt initVal
- endif
- endm
-
- if sizec
- staticCP macro name:req, i, s
- staticD name,<i>,<s>
- endm
- else
- staticCP macro name:req, i, s
- staticW name,<i>,<s>
- endm
- endif
-
- if sized
- staticDP macro name:req, i, s
- staticD name,<i>,<s>
- endm
- else
- staticDP macro name:req, i, s
- staticW name,<i>,<s>
- endm
- endif
-
- endif ; ?NOSTATIC
-
-
- globalB macro name:req, initVal:=<?>, repCount, langType
- ??CM_gbl1 name, langType, initVal, repCount, DB
- endm
-
- globalW macro name:req, initVal:=<?>, repCount, langType
- ??CM_gbl1 name, langType, <initVal>, repCount, DW
- endm
-
- globalD macro name:req, initVal:=<?>, repCount, langType
- ??CM_gbl1 name, langType, <initVal>, repCount, DD
- endm
-
- globalQ macro name:req, initVal:=<?>, repCount, langType
- ??CM_gbl1 name, langType, initVal, repCount, DQ
- endm
-
- globalT macro name:req, initVal:=<?>, repCount, langType
- ??CM_gbl1 name, langType, initVal, repCount, DT
- endm
-
- if sizec
- globalCP macro n,i,s,c
- globalD <n>,<i>,<s>,<c>
- endm
- else
- globalCP macro n,i,s,c
- globalW <n>,<i>,<s>,<c>
- endm
- endif
-
- if sized
- globalDP macro n,i,s,c
- globalD <n>,<i>,<s>,<c>
- endm
- else
- globalDP macro n,i,s,c
- globalW <n>,<i>,<s>,<c>
- endm
- endif
-
-
- ??CM_gbl1 macro name, langType, initVal, repCount:=<1>, kind
- setDefLangType langType
- ifidn defLangType,<C>
- public _&name
- name textequ <_&name>
- _&name kind repCount dup (initVal)
- else
- public name
- name kind repCount dup (initVal)
- endif
- endm
-
-
- ifndef ?NOEXTERN
- .xcref
- .xcref externB, externW, externD, externQ, externT
- .xcref externNP, externFP, externP, externCP, externDP, externA
- .cref
-
- ; externX - define external data of type X
- ;
- ; usage:
- ; externX n,c
- ;
- ; where:
- ; X is the type of the variable: b=byte, w=word, d=dword
- ; q=qword, t=tbyte, cp=code pointer, dp=data pointer
- ; a=absolute, i=int
- ; n is a list of names to be defined
- ; c is the lanague convention. C for C or PASCAL or PLM for
- ; pascal. The default (?PLM flag) will be used if not specified
-
- externA macro names:req, langtype
- ??CM_ex1 <names>, langtype, ABS
- endm
-
- externB macro names:req, langtype
- ??CM_ex1 <names>, langtype, BYTE
- endm
-
- externW macro names:req, langtype
- ??CM_ex1 <names>, langtype, WORD
- endm
-
- externD macro names:req, langtype
- ??CM_ex1 <names>, langtype, DWORD
- endm
-
- externQ macro names:req, langtype
- ??CM_ex1 <names>, langtype, QWORD
- endm
-
- externT macro names:req, langtype
- ??CM_ex1 <names>, langtype, TBYTE
- endm
-
- externNP macro names:req, langtype
- ??CM_ex1 <names>, langtype, NEAR
- endm
-
- externFP macro names:req, langtype
- ??CM_ex1 <names>, langtype, FAR
- endm
-
- if sizec
- externP macro n,c
- externFP <n>,c
- endm
- externCP macro n,c
- externD <n>,c
- endm
- else
- externP macro n,c
- externNP <n>,c
- endm
- externCP macro n,c
- externW <n>,c
- endm
- endif
-
- if sized
- externDP macro n,c
- externD <n>,c
- endm
- else
- externDP macro n,c
- externW <n>,c
- endm
- endif
-
- ??CM_ex1 macro names, langType, kind
- setDefLangType langType
- for name,<names>
- ifidn defLangType,<C>
- name textequ ??CM_Paste(_, name)
- extern ??CM_Paste(_, name):kind
- else
- extern defLangType name:kind
- endif
- endm
- endm
-
- endif ; ?NOEXTERN
-
- ifndef ?NOLABEL
-
- ; labelX - define label of data type X
- ;
-
- labelB macro names:req,langType
- ??CM_lb1 <names>, langType, BYTE
- endm
-
- labelW macro names:req,langType
- ??CM_lb1 <names>, langType, WORD
- endm
-
- labelD macro names:req,langType
- ??CM_lb1 <names>, langType, DWORD
- endm
-
- labelQ macro names:req,langType
- ??CM_lb1 <names>, langType, QWORD
- endm
-
- labelT macro names:req,langType
- ??CM_lb1 <names>, langType, TBYTE
- endm
-
- labelNP macro names:req,langType
- ??CM_lb1 <names>, langType, NEAR
- endm
-
- labelFP macro names:req,langType
- ??CM_lb1 <names>, langType, FAR
- endm
-
- if sizec
- labelP macro n,c
- labelFP <n>,c
- endm
- labelCP macro n,c
- labelD <n>,c
- endm
- else
- labelP macro n,c
- labelNP <n>,c
- endm
- labelCP macro n,c
- labelW <n>,c
- endm
- endif
-
- if sized
- labelDP macro n,c
- labelD <n>,c
- endm
- else
- labelDP macro n,c
- labelW <n>,c
- endm
- endif
-
- ??CM_lb1 macro names:req, langType, kind
- setDefLangType langType
- ?pu = 0
- for name,<names>
- ifidn <name>,<PUBLIC>
- ?pu =1
- else
- ifidn defLangType,<C>
- if ?pu
- public ??CM_Paste(_, name)
- endif
- name textequ ??CM_Paste(_, name)
- ??CM_Paste(_, name) label kind
- else
- if ?pu
- public name
- endif
- name label kind
- endif
- endif
- endm
- endm
-
- endif ; ?NOLABEL
-
-
- ifndef ?NODEF
-
- ; defX - inform the macros that name is of type X
- ;
- ; The given name(s) is flagged to be of the given type.
- ;
- ; This macro is no longer needed.
- ;
-
- for lbl,<defB, defW, defD, defQ, defT, defCP, defDP>
- lbl macro names:req
- endm
- endm
-
- endif ; ?NODEF
-
-
- ifndef ?NOPTR
- ;; regPtr generates information allowing a 32-bit pointer currently
- ;; in a register to be pushed as a parameter to a subroutine using
- ;; the cCall macro.
- ;;
- ;; usage:
- ;; regptr n,s,o
- ;; where:
- ;; n is the name the argument will be known as
- ;; s is the register containing the segment portion
- ;; of the pointer
- ;; o is the register containing the offset portion
- ;; of the pointer
- ;;
- ;; 2/14/85 - made obsolete with farptr
-
- regPtr macro n,s,o
- farPtr n,s,o
- endm
-
-
-
- ;; farPtr generates information allowing a 32-bit pointer to be
- ;; pushed as a parameter to a subroutine using the cCall macro.
- ;;
- ;; usage:
- ;; farptr n,s,o
- ;; where:
- ;; n is the name the argument will be known as
- ;; s is the segment portion of the pointer
- ;; o is the offset portion of the pointer
- ;;
- ;; Note that any cast must have been made in the argument itself
- ;; (i.e. regptr ptr1,ds,<word ptr 3[si]>)
-
-
- farPtr macro n,s,o
- n macro
- push s
- push o
- endm
- endm
- endif ; ?NOPTR
-
-
-
- ;; arg - declare arguements
- ;;
- ;; The given arguments(s) is added to the argument list structure
- ;;
- ;; format:
- ;; arg a
- ;;
- ;; where:
- ;; a is any valid arugment(s) to push
- ;;
- ;; If any element in arglist has not been defined or isn't 16-bit
- ;; register, then a compilete specification must have been given in
- ;; a text equate and a defx also given (if not, you'll pay the penalty!)
- ;;
-
- arg macro args
- ifnb <args>
- ifnb ??CM_ArgList
- ??CM_ArgList textequ ??CM_ArgList, <,>, <args>
- else
- ??CM_ArgList textequ <args>
- endif
- endif
- endm
-
- ;; ?CM_IsIdent - is the arguement a legal identifier?
- ;;
- ;;
- ;; Need to enforce the following additional rules:
- ;; Digit may not be first character
- ;; Assorted other characters may be used
- ;; Dot may be the first character
-
- ?CM_IsIdent macro name:REQ
- LOCAL result
- result = 1
- forc char,<name>
- if ('A' LE '&char') AND ('&char' LE 'Z')
- goto next
- endif
- if ('a' LE '&char') AND ('&char' LE 'z')
- goto next
- endif
- if ('0' LE '&char') AND ('&char' LE '9')
- goto next
- endif
- result = 0
- exitm
- :next
- endm
- exitm %result
- endm
-
-
- ;; @reverse
- ;;
-
- @reverse macro list
- LOCAL newlist
- newlist textequ <>
- for x,<list>
- newlist catstr <x>, <,>, newlist
- endm
- ifnb newlist
- newlist substr newlist, 1, @sizestr(%newlist)-1
- endif
- exitm newlist
- endm
-
-
- ;; ?ap - process arguments and place onto stack
- ;;
- ;; The given argument is processed (type checking) and placed
- ;; on the stack for a pending call. There must be a type
- ;; definition for all arguments (except words). This can be
- ;; done using text equates and the defx macro.
- ;;
-
- ?ap macro n
- ?argl=?argl+2 ;; assume one word is pushed
- if 0 EQ (OPATTR n)
- if ?CM_IsIdent(n)
- ifdef n
- n
- exitm
- endif
- endif
- % .err <'&n' is not valid to push>
- exitm
- else
- i = (TYPE n)
- if i EQ 1 ;; byte type
- push word ptr(n)
- exitm
- endif
-
- if i EQ 2 ;; word type
- push n
- exitm
- endif
-
- if i EQ 4 ;; dword type
- push word ptr (n)[2]
- push word ptr (n)
- ?argl=?argl+2
- exitm
- endif
-
- if i EQ 8 ;; qword type
- push word ptr (n)[6]
- push word ptr (n)[4]
- push word ptr (n)[2]
- push word ptr (n)
- ?argl=?argl+6
- exitm
- endif
-
- push word ptr (n) ;; variable storage
- exitm
- endif
- endm
-
-
- ;; cCall - call a 'c' language procedure
- ;;
- ;; The given procedure is called with the given parameters. If the
- ;; calling convention is C, the arguments are pushed in reverse order,
- ;; and removed after the called procedure returns. If the calling
- ;; convention is PL/M, the arguments are pushed as they were encountered,
- ;; and the called procedure is assumed to have removed them
- ;; from the stack.
- ;;
- ;; The calling convention priority will be:
- ;; 1) that specified on the cCall if present,
- ;; 2) that defined by the target,
- ;; 3) the default (?PLM flag).
- ;;
- ;; format:
- ;; cCall n,<a>,c
- ;;
- ;; where:
- ;; n is the name of the procedure to call
- ;; a are the arguments to be pushed (optional, may be specified
- ;; with the "arg" macro.
- ;; c is the calling convention, C for C, PLM or PASCAL for
- ;; PL/M. The default (?PLM flag) will be used if
- ;; not specified).
- ;;
-
- cCall macro name:req,args,langType
-
- ifnb <args> ;; add any passed in arguments
- arg <args> ;; to the list of arguments
- endif ;; for this procedure
-
- ifnb ??CM_RegSaveList ;; If there are any resgisters
- % for reg,<??CM_RegSaveList> ;; to be saved across the call
- push reg ;; save then on the stack
- endm ;;
- endif ;;
-
- ifnb <langType> ;; If a lang type was specified then
- setDefLangType langType ;; it overrides all common sense
- else
- i = ((OPATTR name) SHR 8) AND 7 ;; Get the lang type from the symbol
- if i EQ 0 ;; No lang type ---
- setDefLangType ;; Use the default lang type
- elseif i EQ 1 ;; C lang type
- defLangType textequ <C> ;;
- elseif i EQ 4 ;; Pascal Lang Type
- defLangType textequ <PASCAL> ;;
- else ;; Unknown lang type
- .err <Unknown lang type specfied for '&name'> ;;
- endif
- endif
-
- ifidn defLangType,<C> ;; If using C calling convention
- ??CM_ArgList textequ @reverse(%??CM_ArgList) ;; then reverse the arguements
- endif ;;
-
- ?argl=0 ;; Clear arguement byte count
-
- % for arg,<??CM_ArgList> ;; Push the procedures arguements
- ?ap <arg> ;; onto the stack. ?ap takes
- endm ;; care of sizing arguements
-
- call name ;; Do the actual call
-
- ifidn defLangType,<C> ;; If this is a C proc and there
- if ?argl NE 0 ;;
- add sp,?argl ;; are parameters then pop them
- endif ;; off the stack
- endif ;;
-
- ifnb ??CM_RegSaveList ;; If there were any saved registers
- ??CM_RegSaveList textequ @reverse(%??CM_RegSaveList) ;; then pop them off the stack
- % for reg,<??CM_RegSaveList> ;; at this point.
- pop reg ;;
- endm ;;
- endif ;;
-
- ??CM_RegSaveList textequ <> ;; Clear out the global state
- ??CM_ArgList textequ <> ;; variable used by the cCall macro
- endm
-
-
-
- ;; save - flag that the indicated registers are to be saved/restored
- ;; on the next cCall invocation
- ;;
- ;; usage:
- ;; save <r>
- ;;
- ;; where:
- ;; r is the list of registers to be saved.
- ;;
- ;; the macro generates a value for the variable ??CM_RegSaveList
- ;;
-
- save macro r
- ??CM_RegSaveList textequ <r>
- endm
-
- ;; parmX - generate reference to parameter(s) on the stack
- ;;
- ;; usage:
- ;; parmX n
- ;; where:
- ;; x is the type of the argument(s) b=byte, w=word, d=dword
- ;; n is the name(s) to be given the parmeter(s).
- ;;
- ;; Byte are considered to be two bytes long for alignment.
- ;;
- ;; The parmd form of the macro generates two equates:
- ;;
- ;; off_name - for accessing the offset (lsw) of the parameter
- ;; seg_name - for accessing the segment (msw) of the parameter
- ;;
-
- parmB macro names:req
- for name,<names>
- ??CM_addParm <&name:BYTE>
- endm
- endm
-
- parmW macro names:req
- for name,<names>
- ??CM_addParm <&name:WORD>
- endm
- endm
-
- parmD macro names:req
- for name,<names>
- ??CM_addParm <&name:DWORD>
- ??CM_Paste(off_, name) textequ <word ptr name[0]>
- ??CM_Paste(seg_, name) textequ <word ptr name[2]>
- endm
- endm
-
- parmQ macro names:req
- for name,<names>
- ??CM_addParm <&name:QWORD>
- endm
- endm
-
- parmT macro names:req
- for name,<names>
- ??CM_addParm <&name:TBYTE>
- endm
- endm
-
- if sizec
- parmCP macro n
- parmD <n>
- endm
- else
- parmCP macro n
- parmW <n>
- endm
- endif
-
- if sized
- parmDP macro n
- parmD <n>
- endm
- else
- parmDP macro n
- parmW <n>
- endm
- endif
-
-
- if 0
- ;; parmR - register parameter
- ;;
- ;; parmR is the macro used for generating register parameters.
- ;; The space allocated for the register parameters will be
- ;; the ?ia (interface adjust) area which is between the old
- ;; BP and the first parameter. Normally this is empty (?ia=0),
- ;; or has the saved ds for a windows far procedure.
- ;;
- ;; Byte and dword register parameters will be allowed.
- ;;
- ;; usage:
- ;; parmR n,r,r2
- ;; where:
- ;; n is the name of the parameter
- ;; r is the register it is in
- ;; r2 is the offset register if a dword
-
-
- ifndef ?NOPARMR
- .xcref
- .xcref ?pr,parmR
- .cref
-
- parmR macro n,r,r2
- ?pr n,r,r2,%?rp,%(?ia+2)
- endm
-
- ;; ?pr - register parameter
- ;;
- ;; ?pr is the actual macro for generating the equates for
- ;; register parameters.
- ;;
- ;; usage:
- ;; parmR n,r,r2,i,o
- ;; where:
- ;; n is the name of the parameter
- ;; r is the register it is in
- ;; r2 is the offset register if a dword
- ;; i is the index of the ?rp to generate
- ;; o is the offset from bp where the parm will be
-
- ?pr macro n,r,r2,i,o
- .xcref
- ifnb <r2> ;;if a dword parameter
- parmR seg_&n,r ;;define segment equate
- parmR off_&n,r2 ;;define offset equate
- n equ (dword ptr [bp-o-2]) ;;define dword equate
- .xcref ?t&n
- ?t&n=4 ;;show a dword to cmacros
- else
- .xcref ?rp&i
- ?rp&i=0 ;;show no register(s)
- ifdef ?&r ;;define register if valid
- ?rp&i=?&r
- endif
-
- if ??? or (?cpd eq 0) or (?rp&i eq 0)
- ??error <invalid parmR encountered: &n,&r>
- exitm
- endif
-
- n equ (word ptr [bp-o]) ;;assume a word register
- ?t&n=2 ;;show a word to cmacros
- irp x,<bh,ch,dh,bl,cl,dl,ah,al>
- if ?&&x eq ?&r ;;if really a byte register
- n equ (byte ptr [bp-o]) ;; then make it a byte
- ?t&n=1 ;;show a byte to cmacros
- exitm
- endif
- endm
- ?ia=?ia+2 ;;show this guy is out there
- ?rp=?rp+1 ;;show one more register parameter
- endif
- .cref
- endm
- endif
- endif
-
- localB macro name
- ??CM_addLocal ??CM_Paste(name, <:BYTE>)
- endm
-
- localW macro name
- ??CM_addLocal ??CM_Paste(name, <:WORD>)
- endm
-
- localD macro name
- ??CM_addLocal ??CM_Paste(name, <:DWORD>)
- off_&name textequ <word ptr name[0]>
- seg_&name textequ <word ptr name[2]>
- endm
-
- localQ macro name
- ??CM_addLocal ??CM_Paste(name, <:QWORD>)
- endm
-
- localT macro name
- ??CM_addLocal ??CM_Paste(name, <:TBYTE>)
- endm
-
- if sizec
- localCP macro n
- localD <n>
- endm
- else
- localCP macro n
- localW <n>
- endm
- endif
-
- if sized
- localDP macro n
- localD <n>
- endm
- else
- localDP macro n
- localW <n>
- endm
- endif
-
- localV macro name,a
- local t1
- t1 catstr <name>, < [>, %a, <]:BYTE>
- % ??CM_addLocal <t1>
- endm
-
-
- ife ?DF
- ;;
- ;; Define all segments that will be used. This will allow the
- ;; assume and groups to be set up at one given place, and also
- ;; allow quick changes to be made
- ;;
-
- createSeg _TEXT,Code,word,public,CODE
- ife ?NODATA
- createSeg _DATA,Data,word,public,DATA,DGROUP
- endif
- endif
-
- ; errnz exp - generate error message if expression isn't zero
- ;
- ; The errnz will generate an error message if the expression "exp"
- ; does not evaluate to zero. This macro is very useful for testing
- ; relationships between items, labels, and data that was coded into
- ; an application.
- ;
- ; errnz <offset $ - offset label> ;error if not at "label"
- ; errnz <eofflag and 00000001b> ;eofflag must be bit 0
- ;
- ; For expressions involving more than one token, the angle brackets
- ; must be used.
- ;
- ; The macro is only evaluated on pass 2, so forward references may be
- ; used in the expression.
-
- errnz macro x ;;display error if expression is <>0
- .errnz x
- endm
-
- ; errn$ label,exp - generate error message if label (exp) <> $
- ;
- ; The errnz will generate an error message if the label and "exp"
- ; does not evaluate to the current value of the location counter.
- ; This macro is very useful for testing relationships between
- ; labels and the location counter that was coded into an application.
- ;
- ; examples: errn$ label ;error if not at "label"
- ; errn$ label,+3 ;error if not three bytes from "label"
- ; errn$ label,-3 ;error if not three bytes past "label"
- ;
- ; If no "exp" is given, it is the same as specifying 0
- ;
- ; The macro is only evaluated on pass 2, so forward references may be
- ; used in the expression.
-
- errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
- errnz <offset $ - offset l x>
- endm
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
- ; Extra macros for the c-runtime package
- ;
- ; Macro for calling another run-time-library function.
- ; Does a PUSH CS/CALL NEAR in compact/large models, except
- ; for QuickC. --PHG, 5-24-89
-
- callcrt MACRO funcname
- ifdef _QC2
- call funcname
- else
- if sizeC
- push cs
- call near ptr (funcname)
- else
- call funcname
- endif
- endif
- ENDM
-
- .cref ; Permit symbols to be listed again
-